package com.gnerv.sylvanas.framework.plugin.mybatis.autoconfigure;

import com.gnerv.sylvanas.framework.plugin.mybatis.constants.DatabaseProductName;
import com.gnerv.sylvanas.framework.plugin.mybatis.extend.DtoExtendResult;
import com.gnerv.sylvanas.framework.plugin.mybatis.extend.MybatisResourceHandler;
import com.gnerv.sylvanas.framework.plugin.mybatis.extend.MybatisSqlSessionFactoryBeanCustomizer;
import com.gnerv.sylvanas.framework.plugin.mybatis.interceptor.CommonParameterHandler;
import com.gnerv.sylvanas.framework.plugin.mybatis.interceptor.CommonParameterInterceptor;
import com.gnerv.sylvanas.framework.plugin.mybatis.interceptor.PrintSqlInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author Gnerv LiGen
 */
@Slf4j
@AutoConfiguration
@EnableConfigurationProperties(FrameworkMybatisConfigProperties.class)
public class FrameworkMybatisAutoConfiguration {

    private final List<DtoExtendResult> dtoExtendResultList;

    public FrameworkMybatisAutoConfiguration(List<DtoExtendResult> dtoExtendResultList) {
        this.dtoExtendResultList = dtoExtendResultList;
    }

    @Bean
    @ConditionalOnMissingBean
    public DatabaseIdProvider databaseIdProvider() {
        VendorDatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties properties = new Properties();
        properties.put(DatabaseProductName.POSTGRESQL, DatabaseProductName.POSTGRESQL.toLowerCase());
        properties.put(DatabaseProductName.MYSQL, DatabaseProductName.MYSQL.toLowerCase());
        properties.put(DatabaseProductName.ORACLE, DatabaseProductName.ORACLE.toLowerCase());
        properties.put(DatabaseProductName.DB2, DatabaseProductName.DB2.toLowerCase());
        properties.put(DatabaseProductName.H2, DatabaseProductName.H2.toLowerCase());
        databaseIdProvider.setProperties(properties);
        return databaseIdProvider;
    }

    @Bean
    public MybatisSqlSessionFactoryBeanCustomizer mybatisSqlSessionFactoryBeanCustomizer(MybatisProperties mybatisProperties) {
        return new MybatisSqlSessionFactoryBeanCustomizer(new MybatisResourceHandler(dtoExtendResultList, mybatisProperties.resolveMapperLocations()));
    }

    @Bean
    public PrintSqlInterceptor printSqlInterceptor() {
        return new PrintSqlInterceptor();
    }

    @Bean
    public CommonParameterInterceptor commonParameterInterceptor(List<CommonParameterHandler> commonParameterHandlerList) {
        return new CommonParameterInterceptor(commonParameterHandlerList);
    }

    @Bean
    public CommonParameterHandler commonParameterHandler() {
        return new CommonParameterHandler() {
            @Override
            public Map<String, Object> getParameters() {
                Map<String, Object> paramMap = new HashMap<>();
                paramMap.put("currentGmtTimestamp", LocalDateTime.now(ZoneOffset.UTC).atZone(ZoneOffset.UTC).toInstant().toEpochMilli());
                return paramMap;
            }
        };
    }

}
